﻿using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using RainEngine;
using RainEngine.Controllers;
using RainEngine.SceneNodes;

namespace Sample03
{
    /// <summary>
    /// 坦克模型控制器，从ModelController类继承，实现了坦克跟随地形的效果
    /// </summary>
    public class tankModelController : ModelController
    {
        #region 构造函数和成员变量 
        
        private tankModel tankModel;  
        SimpleTerrainSceneNode terrain;

        private const int WALK_HEIGHT = 5;        

        /// <summary>
        /// 创建一个新ModelController对象。
        /// </summary>
        /// <param name="engine"></param>
        public tankModelController(RainGE engine,SimpleTerrainSceneNode terrain): base(engine)
        {
            this.terrain=terrain ;
        }
        #endregion
        
        /// <summary>
        /// 主控制逻辑
        /// </summary>
        /// <param name="gameTime"></param>
        public override void ControllerAction(GameTime gameTime)
        {
            if (tankModel == null)
            {
                tankModel = (tankModel)controlledNode;
            }
            //每帧流逝的时间，秒为单位
            float timeDifference = (float)gameTime.ElapsedGameTime.TotalMilliseconds / 1000.0f;
            ProcessInput(timeDifference);
        }
        
        
        private void ProcessInput(float elapsedTime)
        {
            float movement = 0;
            float rotation = 0;

            //坦克相机每帧旋转和移动距离
            float rotationPerFrame = elapsedTime * tankModel.RotationSpeed;
            float movementPerFrame = elapsedTime * tankModel.MovementSpeed;

            if (Input.KeyboardUpPressed || Input.Keyboard.IsKeyDown(Keys.W))
            {
                movement += movementPerFrame;
                
                //轮子的转动角度
                float theta = movementPerFrame / 1.8f;
                tankModel.WheelRotationValue += theta;
            }
            if (Input.KeyboardDownPressed || Input.Keyboard.IsKeyDown(Keys.S))
            {
                movement -= movementPerFrame;

                //轮子的转动角度
                float theta = movementPerFrame / 1.8f;
                tankModel.WheelRotationValue -= theta;
            }
            if (Input.KeyboardRightPressed || Input.Keyboard.IsKeyDown(Keys.D))
            {
                rotation += rotationPerFrame;
                
                //前轮轴的转动角度
                tankModel.SteerRotationValue = -10f;
                if (Input.KeyboardDownPressed)
                    tankModel.SteerRotationValue = 10f;
            }
            if (Input.KeyboardLeftPressed || Input.Keyboard.IsKeyDown(Keys.A))
            {
                rotation -= rotationPerFrame;

                //前轮轴的转动角度
                tankModel.SteerRotationValue = 10f;
                if (Input.KeyboardDownPressed)
                    tankModel.SteerRotationValue = -10f;
            }
            //如果没有左右转弯，则将前轮轴的转动角度设为0
            if (!(Input.KeyboardLeftPressed || Input.KeyboardRightPressed))
                tankModel.SteerRotationValue = 0;

            if (movement != 0 || rotation != 0)
            {
                Vector3 frontLeftOrig = new Vector3(0, 0, 0);
                Vector3 frontRightOrig = new Vector3(-90.54291f, -85.02f, 11.64229f);
                Vector3 backLeftOrig = new Vector3(-123.0109f, -121.891f, -16.23285f);
                Vector3 backRightOrig = new Vector3(123.0109f, -121.891f, -16.23285f);

                Matrix frontLeftMatrix = tankModel.Model.Bones["l_front_wheel_geo"].Transform;
                Matrix frontRightMatrix = tankModel.Model.Bones["r_front_wheel_geo"].Transform;
                Matrix backLeftMatrix = tankModel.Model.Bones["l_back_wheel_geo"].Transform;
                Matrix backRightMatrix = tankModel.Model.Bones["r_back_wheel_geo"].Transform;

                Vector3 frontLeft = Vector3.Transform(frontLeftOrig, frontLeftMatrix * tankModel.Pose.WorldMatrix);
                Vector3 frontRight = Vector3.Transform(frontRightOrig, frontLeftMatrix * tankModel.Pose.WorldMatrix);
                Vector3 backLeft = Vector3.Transform(backLeftOrig, frontLeftMatrix * tankModel.Pose.WorldMatrix);
                Vector3 backRight = Vector3.Transform(backRightOrig, frontLeftMatrix * tankModel.Pose.WorldMatrix);

                Vector3 front = (frontLeft + frontRight) / 2.0f;
                Vector3 back = (backLeft + backRight) / 2.0f;
                Vector3 backToFront = front - back;

                float frontTerHeight = terrain.GetExactHeightAt(front.X, -front.Z);
                float backTerHeight = terrain.GetExactHeightAt(back.X, -back.Z);
                float fbTerHeightDiff = frontTerHeight - backTerHeight;

                float fbAngle = (float)Math.Atan2(fbTerHeightDiff, backToFront.Length());

                Vector3 left = (frontLeft + backLeft) / 2.0f;
                Vector3 right = (frontRight + backRight) / 2.0f;
                Vector3 rightToLeft = left - right;

                float leftTerHeight = terrain.GetExactHeightAt(left.X, -left.Z);
                float rightTerHeight = terrain.GetExactHeightAt(right.X, -right.Z);
                float lrTerHeightDiff = leftTerHeight - rightTerHeight;

                float lrAngle = (float)Math.Atan2(lrTerHeightDiff, rightToLeft.Length());

                //设置坦克车身的旋转
                angle += rotation;
                tankModel.AngleRotation = new Vector3(fbAngle * 30, angle, -lrAngle * 30);
                tankModel.Pose.Rotation = Quaternion.CreateFromYawPitchRoll(MathHelper.ToRadians(-tankModel.AngleRotation.Y), MathHelper.ToRadians(-tankModel.AngleRotation.X), MathHelper.ToRadians(tankModel.AngleRotation.Z));
                tankModel.Pose.SetRotation(ref tankModel.Pose.Rotation);

                Vector3 addVector = Vector3.Transform(Vector3.Forward, Quaternion.CreateFromAxisAngle(Vector3.Up, MathHelper.ToRadians(-tankModel.AngleRotation.Y))) * movement;
                tankModel.Pose.Position -=addVector;
                tankModel.Pose.SetPosition(ref tankModel.Pose.Position);                
            }
            
            Vector3 tempPosition;
            //  检测坦克的高度，如果高度发生变化，则重新设置坦克的高度
            float height = WALK_HEIGHT + terrain.GetExactHeightAt(tankModel.Pose.Position.X, tankModel.Pose.Position.Z);
            float diff = height - tankModel.Pose.Position.Y;
            if (diff != 0)
            {
                tempPosition = new Vector3(tankModel.Pose.Position.X, height, tankModel.Pose.Position.Z);
                tankModel.Pose.SetPosition(ref tempPosition);
            }

            //旋转炮台
            tankModel.TurretRotation -= Input.MouseXMovement * tankModel.MaxCannonSpeed*elapsedTime ;
            //旋转炮管
            tankModel.CannonRotation += Input.MouseYMovement * tankModel.MaxCannonSpeed * elapsedTime;

            //移动相机的位置跟随模型
            tankModel.Scene.Camera.Pose.SetPosition(ref tankModel.Pose.Position);
            tankModel.Scene.Camera.UpdateViewMatrix(true);
        }
    }
}
